#include "Stuff.h"
#include "Quad.h"
#include "State.h"
#include "Input.h"
#include "Color.h"
#include "Movement.h"

// position and rotation of camera
GLdouble fpsTime = 0; 
GLint frameCount = 0;
GLdouble fps = 0; 

void init(void)
{
	glClearColor(0, 0, 0, 0);
	
	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LEQUAL);
	glClearDepth(1.0f);

	glShadeModel(GL_SMOOTH);
	glLineWidth(3.0f);

	// turn off vsync
	glfwSwapInterval(0);

	// lighting
	glColorMaterial(GL_FRONT_AND_BACK, GL_EMISSION);
	glEnable(GL_COLOR_MATERIAL);

	GLfloat mat_specular[] = {1.0, 1.0, 1.0, 1.0};
	GLfloat mat_shininess[] = {50.0};
	GLfloat light_position[] = {50000.0, -10.0, 1.0, 0.0};
	GLfloat spot_direction[] = {1.0f, 0, 0, 0};

    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
	glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
	glLightfv(GL_LIGHT0, GL_POSITION, light_position);
	glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, spot_direction);

	glEnable(GL_LIGHT0);
	
	glMatrixMode(GL_PROJECTION);
	gluPerspective(90.0f, (GLfloat)Config::width / (GLfloat)Config::height, 0.01f, 100.0f);
}

void fixRotation()
{
	if(State::rotation.x > 90.0)
	{
		State::rotation.x = 90.0f;
	}
	if(State::rotation.x < -90.0)
	{
		State::rotation.x = -90.0f;
	}
	if(State::rotation.y < 0)
	{
		State::rotation.y += 360.0;
	}
	if(State::rotation.y >= 360.0)
	{
		State::rotation.y -= 360.0;
	}
}

void update()
{
	State::lastPosition = State::position;

	State::deltaV = (GLfloat)(State::velocity * State::deltaTime);
	State::radianY = (State::rotation.y / 180 * Math::pi);

	Input::update();

	fixRotation();
}

void drawCrosshair()
{
	glPushMatrix();

	glDisable(GL_DEPTH_TEST);
	
	glLoadIdentity();
	glOrtho(0, Config::width, Config::height, 0, 0, 1);
	
	glColorv(Color::red);

	glBegin(GL_LINES);
		glVertex2f(Config::width / 2.0f, (Config::height / 2.0f) - 10.0f);
		glVertex2f(Config::width / 2.0f, (Config::height / 2.0f) + 10.0f); 
		glVertex2f((Config::width / 2.0f) - 10.0f, Config::height / 2.0f);
		glVertex2f((Config::width / 2.0f) + 10.0f, Config::height / 2.0f); 
	glEnd();

	glEnable(GL_DEPTH_TEST);

	glPopMatrix();
}

void draw(void)
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	glRotatef(State::rotation.x, 1.0f, 0, 0);
	glRotatef(State::rotation.y, 0, 1.0f, 0);
	glTranslatef(-State::position.x, -State::position.y, -State::position.z);

	// axes
	glBegin(GL_LINES);
		glColor3f(0, 1.0f, 0);
		glVertex3f(0, 0.25f, 0);
		glVertex3f(0, 2.0f, 0);
		glColor3f(1.0, 0, 0);
		glVertex3f(0, 0.25f, 0);
		glVertex3f(2.0, 0.25f, 0);
		glColor3f(0, 0, 1.0);
		glVertex3f(0, 0.25f, 0);
		glVertex3f(0, 0.25f, 2.0f);
	glEnd();

	drawCrosshair();

	glFlush();
	glfwSwapBuffers();
}

/*
void stats()
{
	if ((currentTime - fpsTime) > 1.0)
	{
		fps = (GLdouble)frameCount / (currentTime - fpsTime);
 
		std::cout << "fps: " << fps << std::endl;
			
		fpsTime = glfwGetTime();
		frameCount = 0;
	}
	else
	{
		frameCount++;
	}
}
*/


void fn3()
{
	std::cout << State::currentTime << std::endl;
}

void fn()
{
	Input::bind(GLFW_KEY_F3, fn3); 
}

void fn2()
{
	Input::unbind(GLFW_KEY_F3); 
}

int main()
{
	int running = GL_TRUE;
	
	if(!glfwInit())
	{
		exit(EXIT_FAILURE);
	}
	
	/*
	GLFWvidmode vidmode;
	glfwGetDesktopMode(&vidmode);
	width = vidmode.Width;
	height = vidmode.Height;
	*/

	if(!glfwOpenWindow(Config::width, Config::height, 0, 0, 0, 0, 0, 0, GLFW_WINDOW))
	{
		glfwTerminate();
		exit(EXIT_FAILURE);
	}
	glfwSetWindowTitle("demo");
	glfwSetWindowPos(1000, 100);

	init();
	 
	Input::bind('W', moveForward);
	Input::bind('A', moveBack);
	Input::bind('S', moveLeft);
	Input::bind('D', moveRight);
	Input::bind(GLFW_KEY_SPACE, moveUp);
	Input::bind(GLFW_KEY_LCTRL, moveDown);
	Input::bind(GLFW_KEY_F1, fn); 
	Input::bind(GLFW_KEY_F2, fn2);
	Input::setMouse(mouseLook);

	glfwDisable(GLFW_MOUSE_CURSOR);
	glfwSetMousePos(0, 0);

	// game loop
	while(running)
	{
		State::currentTime = glfwGetTime();
		State::deltaTime = State::currentTime - State::lastTime;
		
		update();
		draw();

		State::lastTime = State::currentTime;

		running = !glfwGetKey(GLFW_KEY_ESC) && glfwGetWindowParam(GLFW_OPENED);
	}
	
	glfwTerminate();
	exit(EXIT_SUCCESS);
}